import java.lang.*;
import java.io.*;

public class Pipe{
    
    boolean open,empty,full;
    char [] pipe;
    int head,tail;
	
    public Pipe(){
        this.open = true;
        pipe = new char[1024];
        for(int i=0;i<pipe.length;i++){
            pipe[i] = 0;
            
        }
        this.head = 0;
        this.tail = 0;
        full = false;
        empty = true;
        
    }


    public synchronized String readPipe(int n){
         if(n < 0)
        	return null;       
        char[] temp = new char[n];
        int i=0;
        try{

        if(open){

            //check to see if it is empty or not
            if((empty=isEmpty())){
                while(empty){
                    System.out.println("Reader waiting...\n");
                    wait();
                    if(!open)
                        return null;
                }
            }
            
            while(i<n && (pipe[head] != 0)){
                if(head == pipe.length-1)
                    head = 0;
                temp[i] = pipe[head];
                pipe[head] =0;
               	i++;
                head++;
            }
            empty = isEmpty();
            System.out.println(i+" characters read out of "+n+" desired");
            full = isFull();
            notifyAll();
            
            return new String(temp);
        }else{
            return null;
        }

        }catch(Exception e){}
        return null;
    }


    public synchronized int writePipe(String s){
        char [] temp = new char[s.length()];
       
        int i = 0;
        boolean done = false;
        try{
        
            if(open){
                //put chars into temp
                s.getChars(0,s.length(),temp,0);
                while (i<temp.length) {
                    if(pipe[tail] != 0){
                        System.out.println("writer waiting...");
                        full = true;
                        empty = isEmpty();
                        while(full){
                            wait();
                            if(!open)
                                return 0;
                        }
                    }
                    else{
	                    //System.out.print(temp[i]);
                        pipe[tail] = temp[i];
                        i++;
                        tail++;
                        if(tail == pipe.length)
                            tail=0;
                    }
                    
                }
                System.out.println(i + " chars written");
                empty = isEmpty();
                notifyAll();
                     
           

               return s.length();
            }else
                return 0;
        }catch(Exception e){
            System.out.println(e);
        }
         return 0;
        
    }


    public synchronized void closePipe(){
        open = false;
        System.out.println("pipe is officially closed");
        notifyAll();
    }


    public boolean isEmpty(){
        for (int i=0;i<pipe.length;i++) {
            if(pipe[i] != 0)
                return false;
        }
        return true;
    }

    public boolean isFull(){
        for(int i=0;i<pipe.length;i++){
            if(pipe[i] == 0)
                return false;
        }
        return true;
    }

    public static void main(String [] args){
        System.out.println("starting tests.....\n");       	
		
        System.out.println("Test 1: single thread writes multiple times,\nsingle thread reads.");
        Pipe p = new Pipe();
        (new tester(p,1)).start();
        (new tester(p,2)).start();
       	(new tester(p,3)).start();
        
      
    }

}